home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 31
/
Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso
/
Aminet
/
dev
/
c
/
vbccppcsrc.lha
/
vbcc
/
ar
/
archive.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-07
|
10KB
|
399 lines
/* $VER: ar archive.c V0.1 (31.01.98)
*
* This file is part of ar, a portable archive maintanance
* utility for normal and BSD-style archives.
* Copyright (c) 1999 Frank Wille
*
* ar is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
* ar may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v0.1 (31.01.99) phx
* First working version, which only supports 'q' (quick append)
* and 't' (table of contents), reads and writes normals and
* BSD-style archives. Symbol table will not be created!
* v0.0 (29.01.99) phx
* File created.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ar.h"
#include "archive.h"
#include "errors.h"
static const char *armag = ARMAG;
static const char *arfmag = ARFMAG;
static const char *symtab_name = "/ ";
static const char *longnames_name = "// ";
extern size_t filesize(FILE *,char *);
extern void getfstat(struct ArObject *,char *name);
extern char *filepart(char *);
static void make_long_names(struct Archive *);
static struct ArObject *allocArObject(unsigned long);
static bool parse_header(struct Archive *,struct ArObject *,
struct ArHeader *);
struct Archive *ar_create(char *archive_name)
/* create a new, empty achive */
{
struct Archive *ar;
if (ar = malloc(sizeof(struct Archive))) {
memset(ar,0,sizeof(struct Archive));
initlist(&ar->l);
ar->name = archive_name;
}
return (ar);
}
struct Archive *ar_read(char *archive_name)
/* open archive and read all objects */
{
struct Archive *ar = NULL;
struct ArObject *obj;
uint8 *data;
FILE *fh;
char buf[sizeof(struct ArHeader)]; /* assuming sizeof ArHeader > SARMAG */
unsigned long size;
if (fh = fopen(archive_name,"rb")) {
/* first check for "!<arch>\n" id */
if (fread(buf,1,SARMAG,fh) == SARMAG) {
if (!strncmp(buf,armag,SARMAG)) {
if (ar = ar_create(archive_name)) {
/* read all archive members */
while (fread(buf,1,sizeof(struct ArHeader),fh) ==
sizeof(struct ArHeader)) {
if (sscanf(((struct ArHeader *)buf)->ar_size,"%lu",&size) != 1) {
error(EMALFORMARHDR,ar->name,buf);
break;
}
if (obj = allocArObject(size)) {
/* add next member to ar-list */
size = (size + 1) & ~1; /* 16bit alignment */
if (fread(obj->data,1,size,fh) == size) {
if (parse_header(ar,obj,(struct ArHeader *)buf)) {
if (obj!=ar->symbol_tab && obj!=ar->long_names) {
addtail(&ar->l,&obj->n);
ar->entries++;
}
}
else
break;
}
else {
error(EARMEMBREADERR,ar->name,buf);
break;
}
}
else {
error(EOUTOFMEM);
break;
}
}
}
else
error(EOUTOFMEM);
}
else
error(EFORMATERR,archive_name);
}
else
error(EREADERR,archive_name);
fclose(fh);
}
return (ar);
}
struct Archive *ar_readorcreate(char *name,uint32 mod)
{
struct Archive *ar;
if (ar = ar_read(name))
return (ar);
if (!(mod & AR_CREATIGN))
error(ECREATARC,name);
return (ar_create(name));
}
struct ArObject *ar_newmemb(char *name)
/* read a new archive member from file */
{
struct ArObject *obj = NULL;
FILE *fh;
unsigned long size,xxx;
if (fh = fopen(name,"rb")) {
size = (unsigned long)filesize(fh,name);
if (obj = allocArObject(size)) {
if (fread(obj->data,1,size,fh) == size) {
obj->name = filepart(name);
getfstat(obj,name); /* get time, mode, uid, gid */
}
else {
obj = NULL;
error(EREADERR,name);
}
}
fclose(fh);
}
else
error(ENOFILEORDIR,name);
return (obj);
}
void ar_write(struct Archive *ar,uint32 mod)
/* generate symbol table, write archive in normal or BSD format */
/* @@@ FIXME currently the symbol table is not created! */
{
FILE *fh;
if (!(mod & AR_TRUNC) && !(mod & AR_BSD))
make_long_names(ar);
if (fh = fopen(ar->name,"wb")) {
struct ArObject *obj = (struct ArObject *)ar->l.first;
struct ArObject *next;
char namebuf[20];
unsigned long offset = 0;
bool bsdname;
int len;
int maxlen = (mod & AR_BSD) ? 16 : 15;
fprintf(fh,armag);
/* write archive members */
while (next = (struct ArObject *)obj->n.next) {
/* write file name or reference to namebuf */
len = strlen(obj->name);
bsdname = FALSE;
if ((mod & AR_BSD) && !(mod & AR_TRUNC) && len>16) {
bsdname = TRUE;
sprintf(namebuf,"#1/%d",len);
}
else if (!(mod & AR_BSD) && !(mod & AR_TRUNC) && len>15) {
sprintf(namebuf,"/%lu",offset);
offset += len+2;
}
else if (mod & AR_BSD) {
memcpy(namebuf,obj->name,len<16?len+1:16);
namebuf[16] = '\0';
}
else
sprintf(namebuf,"%.15s/",obj->name);
if ((mod & AR_TRUNC) && len > maxlen) {
/* warning: file name was truncated */
char buf[20];
strcpy(buf,namebuf);
buf[maxlen] = '\0';
error(ETRUNCWARN,obj->name,buf);
}
/* write header */
fprintf(fh,"%-16.16s%-12ld%-6u%-6u%-8o%-10lu%2s",
namebuf,obj->time,obj->uid,obj->gid,obj->mode,
bsdname?obj->size+len:obj->size,arfmag);
if (bsdname) /* long name first */
fwrite(obj->name,1,len,fh);
/* write data */
fwrite(obj->data,1,obj->size,fh);
/* alignment */
if (bsdname)
obj->size += len;
if (obj->size & 1)
fprintf(fh,"\n");
obj = next;
}
}
else
error(ECANTWRITE);
}
static void make_long_names(struct Archive *ar)
/* if archive member with a name > 15 chars are present, */
/* allocate a long-names object for them */
{
struct ArObject *obj = (struct ArObject *)ar->l.first;
struct ArObject *next,*lnobj;
int l;
uint32 size = 0;
char *p;
while (next = (struct ArObject *)obj->n.next) {
if ((l = strlen(obj->name)) > 15)
size += l+2;
obj = next;
}
if (size) {
/* create long-names object and copy file names */
if (lnobj = allocArObject(size)) {
lnobj->name = "/";
p = (char *)lnobj->data;
obj = (struct ArObject *)ar->l.first;
while (next = (struct ArObject *)obj->n.next) {
if ((l = strlen(obj->name)) > 15) {
memcpy(p,obj->name,l);
p += l;
*p++ = '/';
*p++ = '\n';
}
obj = next;
}
if (size & 1)
*p = '\n';
addhead(&ar->l,&lnobj->n);
ar->entries++;
}
}
}
static struct ArObject *allocArObject(unsigned long size)
{
struct ArObject *obj;
uint8 *data;
if ((obj = malloc(sizeof(struct ArObject))) &&
(data = malloc((size+1)&~1))) {
obj->data = data;
obj->size = size;
}
else
error(EOUTOFMEM);
return (obj);
}
static bool parse_header(struct Archive *ar,struct ArObject *obj,
struct ArHeader *hdr)
/* check header and store its informations into ArObject */
{
if (!strncmp(hdr->ar_fmag,arfmag,2)) {
obj->time = (time_t)strtoul(hdr->ar_time,NULL,10);
obj->uid = (uint16)strtoul(hdr->ar_uid,NULL,10);
obj->gid = (uint16)strtoul(hdr->ar_gid,NULL,10);
obj->mode = (uint16)strtoul(hdr->ar_mode,NULL,8); /* octal */
if (!strncmp(hdr->ar_name,symtab_name,2) || /* normal sym table */
!strncmp(hdr->ar_name,"__.SYMDEF ",10)) { /* BSD symbol table */
ar->symbol_tab = obj;
obj->name = (char *)symtab_name;
return (TRUE);
}
else if (!strncmp(hdr->ar_name,longnames_name,3)) { /* long names */
ar-